<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>node.js的学习 | 树洞</title><meta name="author" content="计算机学士&amp;化工硕士"><meta name="copyright" content="计算机学士&amp;化工硕士"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="让实现目标有迹可循，同时用来鞭策自己。">
<meta property="og:type" content="article">
<meta property="og:title" content="node.js的学习">
<meta property="og:url" content="https://baozi0625.gitee.io/tree-cave/2023/08/07/nodeJs/index.html">
<meta property="og:site_name" content="树洞">
<meta property="og:description" content="让实现目标有迹可循，同时用来鞭策自己。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg">
<meta property="article:published_time" content="2023-08-06T16:00:00.000Z">
<meta property="article:modified_time" content="2023-08-30T14:33:45.158Z">
<meta property="article:author" content="计算机学士&amp;化工硕士">
<meta property="article:tag" content="node.js">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg"><link rel="shortcut icon" href="/tree-cave/img/favicon.png"><link rel="canonical" href="https://baozi0625.gitee.io/tree-cave/2023/08/07/nodeJs/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//fonts.googleapis.com" crossorigin=""/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/tree-cave/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;display=swap" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
  root: '/tree-cave/',
  algolia: undefined,
  localSearch: {"path":"/tree-cave/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: true,
    post: true
  },
  runtime: '天',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: {"limitCount":50,"languages":{"author":"作者: 计算机学士&化工硕士","link":"链接: ","source":"来源: 树洞","info":"著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"}},
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#1f1f1f","position":"bottom-left"},
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: true,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'node.js的学习',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-08-30 22:33:45'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><script>(()=>{
  const $loadingBox = document.getElementById('loading-box')
  const $body = document.body
  const preloader = {
    endLoading: () => {
      $body.style.overflow = ''
      $loadingBox.classList.add('loaded')
    },
    initLoading: () => {
      $body.style.overflow = 'hidden'
      $loadingBox.classList.remove('loaded')
    }
  }

  preloader.initLoading()
  window.addEventListener('load',() => { preloader.endLoading() })

  if (false) {
    document.addEventListener('pjax:send', () => { preloader.initLoading() })
    document.addEventListener('pjax:complete', () => { preloader.endLoading() })
  }
})()</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://s2.loli.net/2023/06/20/PkXRYIvxGBrtHZA.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/tree-cave/archives/"><div class="headline">文章</div><div class="length-num">14</div></a><a href="/tree-cave/tags/"><div class="headline">标签</div><div class="length-num">11</div></a><a href="/tree-cave/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/tree-cave/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 休闲</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/tree-cave/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/tree-cave/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg')"><nav id="nav"><span id="blog-info"><a href="/tree-cave/" title="树洞"><span class="site-name">树洞</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/tree-cave/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 休闲</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/tree-cave/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/tree-cave/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/tree-cave/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">node.js的学习</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-08-06T16:00:00.000Z" title="发表于 2023-08-07 00:00:00">2023-08-07</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-08-30T14:33:45.158Z" title="更新于 2023-08-30 22:33:45">2023-08-30</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/tree-cave/categories/node-js/">node.js</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="node.js的学习"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="记录node-js的学习过程"><a href="#记录node-js的学习过程" class="headerlink" title="记录node.js的学习过程"></a><center>记录node.js的学习过程</center></h1><h2 id="1-异步以及promise"><a href="#1-异步以及promise" class="headerlink" title="1.异步以及promise"></a>1.异步以及promise</h2><p>首先node是类似于javaScript语言的，但是它是用在服务器上的。它与java不同，是一个单线程的。它使用异步的方式来解决多线程的需求的。【单线程是从上到下依次执行代码，那么我有一个语句需要很久才可以执行完，但是它下面的语句执行不需要上面的结果出来之后再执行，这时候就用到了异步。像java的话可以再开启一个线程来单独完成下边的语句】</p>
<p>异步的话又不可以去使用return去返回函数的执行结果，那么就需要使用回调函数来返回数据，如果最初的方式来无限回调就会出现很可怕的回调地狱导致代码很难梳理和阅读。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//未引入promise</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">a, b, cb</span>) &#123;</span><br><span class="line">	<span class="title function_">cb</span>(a + b)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">sum</span>(<span class="number">123</span>, <span class="number">456</span>, <span class="function">(<span class="params">result</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="title function_">sum</span>(result, <span class="number">7</span>, <span class="function">(<span class="params">result</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="title function_">sum</span>(result, <span class="number">8</span>, <span class="function"><span class="params">result</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="title function_">sum</span>(result, <span class="number">9</span>, <span class="function"><span class="params">result</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">sum</span>(result, <span class="number">10</span>, <span class="function"><span class="params">result</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">log</span>(result)</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>这时就需要引入promise了。promise拥有一套特殊的存取数据的方式，它可以存储异步调用的结果。</p>
<p>使用构造函数来整一个promise，构造函数中需要一个构造器（函数）作为参数,像下面这样：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> promise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">() =&gt;</span> &#123;&#125;)</span><br></pre></td></tr></table></figure>

<p>这个作为promise函数参数的回调函数里面也有两个参数：resolve 和 reject 是两个函数，通过这两个函数可以向Promise中存储数据【resolve 执行正常时存储数据，reject 执行异常时存储数据，最终结果都是在promise.result中】</p>
<p><strong>存入数据：</strong>调用两个参数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> promise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">//存入：</span></span><br><span class="line">    <span class="comment">// reject(&quot;哈哈&quot;)</span></span><br><span class="line">    <span class="comment">// resolve(&quot;哈哈&quot;)</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p><strong>读取数据：</strong> <strong>通过Promise的实例方法then来读取Promise中存储的数据</strong>，then需要两个回调函数作为参数，回调函数用来获取Promise中的数据，通过resolve存储的数据，会调用第一个函数返回，可以在第一个函数中编写处理数据的代码。通过reject存储的数据或者出现异常时，会调用第二个函数返回 可以在第二个函数中编写处理异常的代码。</p>
<p>then相当于为Promise设置了一个回调函数，当Promise中的数据处理完毕时，便会调用then所设置的回调函数来继续后续任务。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">promise.<span class="title function_">then</span>(<span class="function">(<span class="params">result</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;1&quot;</span>, result)</span><br><span class="line">&#125;, <span class="function">(<span class="params">reason</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;2&quot;</span>, reason)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>这里用了then感觉比之前使用回调函数还要麻烦，但是用了then就可以在合适的时间来去获取到结果【当Promise创建时，PromiseState初始值为pending，当通过resolve存储数据时 PromiseState 变为fulfilled（完成）PromiseResult变为存储的数据。当通过reject存储数据或出错时 PromiseState 变为rejected（拒绝，出错了） PromiseResult变为存储的数据 或 异常对象。当我们通过then读取数据时，相当于为Promise设置了回调函数，如果PromiseState变为fulfilled，则调用then的第一个回调函数来返回数据，如果PromiseState变为rejected，则调用then的第二个回调函数来返回数据】</p>
<p>此外还有两个实例方法：catch() 就是一个专门处理Promise异常的方法。finally()通常用来编写一些无论成功与否都要执行代码。</p>
<hr>
<p><strong>使用promise来改写回调地狱:</strong></p>
<p>首先需要了解一些东西：</p>
<ol>
<li>promise中的then()以及catch()都会返回一个新的promise</li>
<li>then方法和catch方法的回调函数中的返回值会成为他们返回的新的promise中存储的数据</li>
<li>对Promise进行链式调用时，后边的方法（then和catch）读取的是上一步的执行后存储在promise内的结果。如果上一步的执行结果不是当前想要的结果，则跳过当前的方法。当Promise出现异常时，而整个调用链中没有出现catch，则异常会向外抛出。</li>
</ol>
<p>这个时候改写上面未用promise的回调地狱就会简单很多：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">a,b</span>)&#123;</span><br><span class="line">    <span class="comment">//套路 直接返回一个promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="comment">//这里写原本的异步代码</span></span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">()=&gt;</span>&#123;</span><br><span class="line">            <span class="comment">//将结果存入到promise中</span></span><br><span class="line">            <span class="title function_">resolve</span>(a+b)</span><br><span class="line">        &#125;,<span class="number">1000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//调用sum函数 返回的是一个promise 取值调用then方法</span></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">123</span>,<span class="number">456</span>)</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">result</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> reslut+<span class="number">7</span></span><br><span class="line">    <span class="comment">//这时候我想让123+456+7的结果加8【then中返回的数据存在了它返回的新的promise中所以可以再次调用then方法来做】</span></span><br><span class="line">	&#125;)</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">result</span>=&gt;</span>result+<span class="number">8</span>)<span class="comment">//这里用的es6写法，作用同上边等价</span></span><br><span class="line"><span class="comment">//如果有多次就再多.then几次链式调用</span></span><br></pre></td></tr></table></figure>

<p><strong>注意点：</strong> </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Promise</span>的静态方法&lt;==&gt;无需实例化一个promise也可以使用这些方法</span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">resolve</span>() 创建一个立即完成的<span class="title class_">Promise</span></span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">reject</span>() 创建一个立即拒绝的<span class="title class_">Promise</span></span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">all</span>([...]) 同时返回多个<span class="title class_">Promise</span>的执行结果</span><br><span class="line">            其中有一个报错，就返回错误</span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">allSettled</span>([...]) 同时返回多个<span class="title class_">Promise</span>的执行结果(无论成功或失败)</span><br><span class="line">           &#123;<span class="attr">status</span>: <span class="string">&#x27;fulfilled&#x27;</span>, <span class="attr">value</span>: <span class="number">579</span>&#125;</span><br><span class="line">           &#123;<span class="attr">status</span>: <span class="string">&#x27;rejected&#x27;</span>, <span class="attr">reason</span>: <span class="string">&#x27;哈哈&#x27;</span>&#125;</span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">race</span>([...]) 返回执行最快的<span class="title class_">Promise</span>（不考虑对错）</span><br><span class="line">        <span class="title class_">Promise</span>.<span class="title function_">any</span>([...]) 返回执行最快的完成的<span class="title class_">Promise</span></span><br></pre></td></tr></table></figure>

<p>此外：</p>
<p>1.当Promise出现异常时，而整个调用链中没有出现catch，则异常会向外抛出。</p>
<p>2.当主动throw出来异常时，后面代码不再执行，但是如果是catch后面的代码的话，他还是会执行的。</p>
<hr>
<p><strong>关于宏任务与微任务：</strong></p>
<p>js是单线程的，它的运行是基于事件循环机制的。在js中包含有一个调用栈、一个宏任务队列以及一个微任务队列。其中调用栈中的是要执行的代码【全局作用域中的代码都属于调用栈中】，优先级最高。当调用栈中的代码执行完毕【调用栈为空时】，接下来会将宏任务队列中的任务代码依次进栈出栈执行。最后宏任务队列中的任务代码执行完毕后【宏任务队列为空时】，会将微任务队列中的任务代码依次进调用栈出调用栈来执行【一个任务代码进栈之后立马出栈执行任务】。</p>
<p>宏任务队列：大部分的代码都会在宏任务队列中</p>
<p>微任务队列：promise的回调函数【then、catch、finally】都属于微任务队列</p>
<p><strong>注意：</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">     Promise的执行原理</span></span><br><span class="line"><span class="comment">        - Promise在执行，then就相当于给Promise了回调函数</span></span><br><span class="line"><span class="comment">            当Promise的状态从pending 变为 fulfilled时，</span></span><br><span class="line"><span class="comment">                then的回调函数会被放入到任务队列中</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    promise.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">()=&gt;</span>&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="title function_">queueMicrotask</span>(<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br><span class="line">&#125;) 用来向微任务队列中添加一个任务</span><br><span class="line">queueMicrotask与跟它同一级别的promise都在微任务队列中，promise在前，它先执行，执行它它做的事情是往消息队列中在添加一个微任务（在queueMicrotask的后面）</span><br><span class="line">所以显示出来的结果是<span class="number">2</span>   <span class="number">1</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>));</span><br><span class="line"></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>));</span><br><span class="line"></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">4</span>)));</span><br><span class="line">这里是微任务里面的宏任务，执行promise后，它会将() =&gt; <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">4</span>))放入宏任务队列</span><br><span class="line"></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">5</span>));</span><br><span class="line"></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">6</span>));</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">7</span>);</span><br></pre></td></tr></table></figure>



<hr>
<p><strong>_async与await：</strong>让我们可以用同步代码的编写格式来编写异步代码</p>
<p>asyn可以快速的创建异步函数，创建的这个异步函数的返回值会自动封装到一个Promise中返回【console.log一下这个函数的执行结果打印出来的就是一个promise，存储时使用的是resolve，用then方法取值时使用的是第一个回调函数，可以这么简单的理解】</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>)&#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>())</span><br><span class="line"><span class="comment">//Promise &#123;[[PromiseState]]: &#x27;fulfilled&#x27;, [[PromiseResult]]: 10, Symbol(async_id_symbol): 5, Symbol(trigger_async_id_symbol): 1&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">a，b</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> a+b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//参数为回调函数，回调函数想不起来这种就去看箭头函数</span></span><br><span class="line"><span class="title function_">fn</span>(<span class="number">3</span>，<span class="number">5</span>).<span class="title function_">then</span>(<span class="function"><span class="params">result</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(result)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//打印结果为8</span></span><br></pre></td></tr></table></figure>

<p>像这种如果我还想执行上面那种链式的回调，这个时候就有了一种更为简洁且好理解的方式，使用await</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>)&#123;</span><br><span class="line"><span class="comment">// 当我们通过await去调用异步函数时，它会暂停代码的运行，直到异步代码执行有结果时，才会将结果赋值给result，防止了由于赋值语句在异步结果出来前执行，导致的赋值为undefind的情况</span></span><br><span class="line"><span class="comment">// 注意 await只能用于 async声明的异步函数中，或es模块的顶级作用域中</span></span><br><span class="line"><span class="comment">// await阻塞的知识异步函数内部的代码，不会影响外部代码</span></span><br><span class="line"><span class="comment">//使用promise的then方法还需要写两个回调函数作为参数才可以对应进行取值，await直接得到的就是then方法中第一个作为参数的回调函数中取出来的值。这样就避免了使用链式来写，可以使用同步代码的方式来写异步代码，同时避免了获取不到异步代码中值的问题</span></span><br><span class="line"><span class="comment">// 通过await调用异步代码时，需要通过try-catch来处理异常</span></span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> result = <span class="keyword">await</span> <span class="title function_">sum</span>(<span class="number">123</span>, <span class="number">456</span>)</span><br><span class="line">    result = <span class="keyword">await</span> <span class="title function_">sum</span>(result, <span class="number">7</span>)</span><br><span class="line">    result = <span class="keyword">await</span> <span class="title function_">sum</span>(result, <span class="number">8</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(result)</span><br><span class="line">&#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;出错了~~&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>注意：</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fn4</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line">    <span class="comment">/* </span></span><br><span class="line"><span class="comment">        当我们使用await调用函数后，当前函数后边的所有代码</span></span><br><span class="line"><span class="comment">            会在当前函数执行完毕后，被放入到微任务队里中</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// await后边的所有代码，都会放入到微任务队列中执行</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">4</span>)</span><br><span class="line"><span class="comment">//结果为：1 2 4 3 </span></span><br></pre></td></tr></table></figure>

<p>因为await后边的所有代码，都会放入到微任务队列中执行。放到微队列任务之后，当前调用栈中还不为空有一个打印输出语句，所以先清空了调用栈中的再去执行微任务队列中的。</p>
<hr>
<h2 id="2-模块化"><a href="#2-模块化" class="headerlink" title="2.模块化"></a>2.模块化</h2><blockquote>
<p>CommonJs是node原生支持的一种模块化规范并不是es的模块化规范。在CommonJs中一个js文件就是一个模块。(node中默认的就是CommonJs的模块化规范)</p>
</blockquote>
<p><strong>模块的引入：</strong></p>
<p>使用require(“模块的路径”)来引入模块，这里路径的书写方式根据引入的模块类型不同分为：</p>
<ul>
<li><p>自定义模块：路径要以.&#x2F;或者..&#x2F;来开头（.&#x2F;这种绝对路径在实际中不可取）</p>
<p>在CommonJS中，如果省略的js文件的扩展名node会自动为文件补全扩展名     .&#x2F;m1.js 如果没有js 它会寻找 .&#x2F;m1.json</p>
<p>js –&gt; json –&gt; node（特殊）</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> m1 = <span class="built_in">require</span>(<span class="string">&quot;./m1&quot;</span>)</span><br></pre></td></tr></table></figure>

<ul>
<li><p>核心模块&#x2F;第三方模块</p>
<p>直接写核心模块的名字即可，也可以在核心模块前添加 node: 来加快查找模块的速度。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// const path = require(&quot;path&quot;)</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;node:path&quot;</span>)</span><br></pre></td></tr></table></figure></li>
</ul>
<p>模块引入之后如果在模块的那个js文件中并没有向外去暴露东西的话，那么require返回的就是一个空对象（在定义模块时，模块中的内容默认是不能被外部看到的）。在模块里面向外暴露用的是export（也可以说export就是require函数的返回值）</p>
<p><strong>模块中内容的暴露：</strong></p>
<ul>
<li><p>可以通过exports 一个一个的导出值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">a</span> = <span class="string">&quot;孙悟空&quot;</span></span><br><span class="line"><span class="built_in">exports</span>.<span class="property">b</span> = &#123;<span class="attr">name</span>:<span class="string">&quot;白骨精&quot;</span>&#125;</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">c</span> = <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;哈哈&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>也可以直接通过module.exports同时导出多个值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="string">&quot;哈哈&quot;</span>,</span><br><span class="line">    <span class="attr">b</span>: [<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">7</span>],</span><br><span class="line">    <span class="comment">//对于要给模块内传数据的问题可以用暴露函数的方法，利用参数传值</span></span><br><span class="line">    <span class="attr">c</span>: <span class="function">() =&gt;</span>&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">111</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
<p><strong>文件夹模块：</strong></p>
<p>就是我有一个大的模块，如果都写一个js文件中的话就会显得很臃肿，那么这时候我可以整一个文件夹来放多个文件，最后新建一个文件夹模块的默认入口index.js文件，在这个文件中去require那些其它的文件。引入时只需要在路径那写上.&#x2F;文件夹名就可以。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = <span class="built_in">require</span>(<span class="string">&quot;./a&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> b = <span class="built_in">require</span>(<span class="string">&quot;./b&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> c = <span class="built_in">require</span>(<span class="string">&quot;./c&quot;</span>)</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">    <span class="attr">a</span>:a,</span><br><span class="line">    <span class="attr">b</span>:b,</span><br><span class="line">    <span class="attr">c</span>:c,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>引入：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> hello = <span class="built_in">require</span>(<span class="string">&quot;./hello&quot;</span>)</span><br></pre></td></tr></table></figure>

<hr>
<blockquote>
<p>ES6的模块化：（CommonJs用的多）</p>
<p>通过ES模块化，导入的内容都是常量（导入进来之后不能修改），对象内的属性除外</p>
<p>es模块都是运行在严格模式下的，ES模块化，在浏览器中同样支持，但是通常我们不会直接使用，通常都会结合打包工具使用</p>
</blockquote>
<p><strong>定义:</strong></p>
<ol>
<li>创建文件时以.mjs为扩展名</li>
<li>修改package.json将模块化规范设置为ES模块，当我们设置 “type”: “module” 当前项目下所有的js文件都默认为es module</li>
</ol>
<p><strong>向外部导出内容</strong>：export</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 向外部导出内容</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> a = <span class="number">10</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> b = <span class="string">&quot;孙悟空&quot;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> c = &#123; <span class="attr">name</span>: <span class="string">&quot;猪八戒&quot;</span> &#125;</span><br><span class="line"><span class="comment">// 设置默认导出， 一个模块中只有一个默认导出(这里举例默认导出一个函数)</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> a + b</span><br><span class="line"> &#125;</span><br><span class="line"><span class="comment">//默认导出时后面跟一个值</span></span><br><span class="line"><span class="keyword">let</span> d = <span class="number">20</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> d </span><br></pre></td></tr></table></figure>

<p> <strong>导入：</strong></p>
<p>es模块不能省略扩展名（官方标准）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//最简单的，仅仅导进来模块，但模块内的东西没进来</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;./m4.mjs&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//完整的写法</span></span><br><span class="line"><span class="keyword">import</span> &#123; a, b, c &#125; <span class="keyword">from</span> <span class="string">&quot;./m4.mjs&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过as来指定别名</span></span><br><span class="line"><span class="comment">// import &#123; a as hello, b, c &#125; from &quot;./m4.mjs&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 开发时要尽量避免import * 情况</span></span><br><span class="line"><span class="comment">// import * as m4 from &quot;./m4.mjs&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 导入模块的默认导出</span></span><br><span class="line"><span class="comment">// 默认导出的内容，可以随意命名（就是我这里可以不用sum非得和那边导出的一样，也就是默认导出不要写进&#123;&#125;中，命名导出就写到&#123;&#125;内）</span></span><br><span class="line"><span class="comment">// import sum, &#123; a &#125; from &quot;./m4.mjs&quot;</span></span><br></pre></td></tr></table></figure>

<hr>
<blockquote>
<p>核心模块：</p>
</blockquote>
<p><strong>process：</strong></p>
<p>表示当前的node进程，通过该对象可以获取进程的信息，或者对进程做各种操作</p>
<ul>
<li>使用：</li>
</ul>
<ol>
<li>process是一个全局变量，可以直接使用</li>
<li>有哪些属性和方法：<br>   process.exit()：结束当前进程，终止node<br>   process.nextTick(callback[, …args])：将函数插入到 tick队列中，tick队列中的代码，会在下一次事件循环之前执行，会在微任务队列和宏任务队列中任务之前执行</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">process.<span class="title function_">nextTick</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>) <span class="comment">// tick队列</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<ul>
<li>事件执行顺序：</li>
</ul>
<p>调用栈，tick队列， 微任务队列， 宏任务队列</p>
<p><strong>path:</strong></p>
<p>表示路径，可以通过path来获取各种路径，要使用path，首先需要对其进行引入</p>
<ul>
<li><p>常用方法：</p>
<p>path.resolve([…paths])： 用来生成一个绝对路径</p>
<p>如果直接调用resolve，则返回当前的工作目录，<strong>注意，我们通过不同的方式执行代码时，它的工作目录是有可能发生变化的</strong></p>
</li>
<li><p>注意事项：</p>
<p>如果将一个相对路径作为参数，则resolve会自动将其转换为绝对路径，此时根据工作目录的不同，它所产生的绝对路径也不同。所以一般会将一个绝对路径作为第一个参数，一个相对路径作为第二个参数，这样它会自动计算出最终的路径。</p>
</li>
<li><p>代码：</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//引入</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;node:path&quot;</span>)</span><br><span class="line"><span class="comment">// 最终形态</span></span><br><span class="line"><span class="comment">// 以后在使用路径时，尽量通过path.resolve()来生成路径,__dirname:获取当前的文件所在的绝对路径</span></span><br><span class="line"><span class="comment">// const result = path.resolve(__dirname, &quot;./hello.js&quot;)</span></span><br></pre></td></tr></table></figure>

<p><strong>fs：</strong></p>
<p>用来帮助node来操作磁盘中的文件，也就是所谓的I&#x2F;O，input output</p>
<ul>
<li>使用：</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用fs模块，同样需要引入</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&quot;node:fs/promises&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> &#123; buffer &#125; = <span class="built_in">require</span>(<span class="string">&quot;stream/consumers&quot;</span>)</span><br></pre></td></tr></table></figure>

<ul>
<li>方法：（举例一个，其余的到时候查文档去）</li>
</ul>
<ol>
<li>fs.readFile() 异步读取文件</li>
</ol>
<p>   当我们通过fs模块读取磁盘中的数据时，读取到的数据总会以Buffer对象的形式返回,Buffer是一个临时用来存储数据的缓冲区</p>
   <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//回调函数的方式</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(</span><br><span class="line">    path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;./hello.txt&quot;</span>),</span><br><span class="line">    <span class="function">(<span class="params">err, buffer</span>) =&gt;</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;出错了~&quot;</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(buffer.<span class="title function_">toString</span>())</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">        Promise版本的fs的方法（一般都用这种）</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;./hello.txt&quot;</span>))</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">buffer</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(buffer.<span class="title function_">toString</span>())</span><br><span class="line">&#125;)</span><br><span class="line">    .<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;出错了~&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//async和await的方式</span></span><br><span class="line">; (<span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> buffer = <span class="keyword">await</span> fs.<span class="title function_">readFile</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;./hello.txt&quot;</span>))</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(buffer.<span class="title function_">toString</span>())</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;出错了~~&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure>

<ol start="2">
<li><p>fs.readFileSync() 同步的读取文件的方法，会阻塞后边代码的执行</p>
</li>
<li><p>fs.appendFile() 创建新文件，或将数据添加到已有文件中</p>
</li>
<li><p>fs.mkdir() 创建目录</p>
</li>
<li><p>fs.rmdir() 删除目录</p>
</li>
<li><p>fs.rm() 删除文件</p>
</li>
<li><p>fs.rename() 重命名</p>
</li>
<li><p>fs.copyFile() 复制文件</p>
</li>
</ol>
<h2 id="3-包管理器NPM"><a href="#3-包管理器NPM" class="headerlink" title="3.包管理器NPM"></a>3.包管理器NPM</h2><p>包就是一套编好的代码，我们拿过来就可以用。npm是一个包的大仓库，需要用什么就从上面下载拿下来然后引入。</p>
<p><strong>package.json：</strong></p>
<p>package.json是包的描述文件，node中通过该文件对项目进行描述，每一个node项目必须有package.json。</p>
<p>scripts:</p>
<ul>
<li>可以自定义一些命令，直接通过npm来执行这些命令</li>
<li>start 和 test 可以直接通过 npm start npm test执行<br>   通过npm run xxx 执行</li>
</ul>
<p><strong>npm：</strong></p>
<ol>
<li>​    npm init 初始化项目，创建package.json文件（需要回答问题）</li>
<li>​    npm init -y 初始化项目，创建package.json文件（所有值都采用默认值）</li>
<li>​    npm install 包名 将指定包下载到当前项目中</li>
</ol>
<p>install时发生了什么？</p>
<p>​        ① 将包下载当前项目的node_modules目录下</p>
<p>​        ② 会在package.json的dependencies属性中添加一个新属性</p>
<p>​          “lodash”: “^4.17.21”</p>
<p>​        ③ 会自动添加package-lock.json文件</p>
<p>​          帮助加速npm下载的，不用动他</p>
<p>npm install 自动安装所有依赖</p>
<p>npm install 包名 -g 全局安装</p>
<p>​      - 全局安装是将包安装到计算机中</p>
<p>​      - 全局安装的通常都是一些工具</p>
<p>npm uninstall 包名 卸载  </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">    引入从npm下载的包时，不需要书写路径，直接写包名即可</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> _ = <span class="built_in">require</span>(<span class="string">&quot;lodash&quot;</span>)</span><br></pre></td></tr></table></figure>

<p>为了快速下载包可以使用npm在国内的镜像</p>
<p>npm镜像：</p>
<p>npm的仓管的服务器位于国外，有时候并不是那么的好使，解决这个问题，可以在npm中配置一个镜像服务器</p>
<ul>
<li>镜像的配置：<br>① 在系统中安装cnpm（我自己不太推荐大家使用）<br>npm install -g cnpm –registry&#x3D;<a target="_blank" rel="noopener" href="https://registry.npmmirror.com/">https://registry.npmmirror.com</a><br>② 彻底修改npm仓库地址（我个人习惯的使用方式）<br>npm set registry <a target="_blank" rel="noopener" href="https://registry.npmmirror.com/">https://registry.npmmirror.com</a></li>
<li>还原到原版仓库<br>   npm config delete registry<br>   想从国外安装时使用npm，从国内镜像安装时使用cnpm</li>
</ul>
<h2 id="4-网络通信及http协议（超哥课堂笔记）"><a href="#4-网络通信及http协议（超哥课堂笔记）" class="headerlink" title="4.网络通信及http协议（超哥课堂笔记）"></a>4.网络通信及http协议（超哥课堂笔记）</h2><h2 id="5-express"><a href="#5-express" class="headerlink" title="5.express"></a>5.express</h2><blockquote>
<p>node中的服务器软件，通过它可以快速的在node中搭建一个web服务器。</p>
</blockquote>
<p> <strong>注意：</strong></p>
<ol>
<li>一切皆对象，服务器在程序中就是以对象的形式存在，想干什么事之前先找对象。</li>
<li>凡是创建node项目都遵循一个套路，①创建完一个项目，先用包管理器执行一下初始化命令，整出来package.json这个文件。②入口文件通常叫index.js</li>
<li>在服务器中路径写的是”&#x2F;“代表根目录</li>
</ol>
<ul>
<li><strong>安装express：</strong></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install express --save</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>引入及使用：</strong></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 引入express</span></span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&quot;express&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取服务器的实例（对象）</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//配置路由</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">    为服务器设置路由，路由可以根据不同的请求方式和请求地址来处理用户的请求,路由的回调函数执行时，会接收到三个参数,第一个 request 第二个 response 第三个 next</span></span><br><span class="line"><span class="comment">    app.METHOD(...)</span></span><br><span class="line"><span class="comment">    METHOD 可以是 get 或 post ...</span></span><br><span class="line"><span class="comment">    在路由中，应该做两件事</span></span><br><span class="line"><span class="comment">    读取用户的请求（request）</span></span><br><span class="line"><span class="comment">    req 表示的是用户的请求信息（请求报文），通过req可以获取用户传递数据</span></span><br><span class="line"><span class="comment">    console.log(req.url)</span></span><br><span class="line"><span class="comment">    根据用户的请求返回响应（response）</span></span><br><span class="line"><span class="comment">    res 表示的服务器发送给客户端的响应信息</span></span><br><span class="line"><span class="comment">    可以通过res来向客户端返回数据</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/hello&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;有人访问我了~&quot;</span>)</span><br><span class="line">    <span class="comment">// sendStatus() 向客户端发送响应状态吗</span></span><br><span class="line">    <span class="comment">// status() 用来设置响应状态吗，但是并不发送</span></span><br><span class="line">    <span class="comment">// send() 设置并发送响应体</span></span><br><span class="line">    <span class="comment">// res.sendStatus(404)</span></span><br><span class="line">    <span class="comment">// res.status(200)</span></span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&quot;&lt;h1&gt;这是我的第一个服务器&lt;/h1&gt;&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">    如果客户端无论访问哪个路由都会做一些同样的事情（权限检查，是否登录...），那么我们在express可以使用app.use来定义一个中间件，和路由很像，用法很像，但是路由不区分请求的方式，只看路径，会匹配所有请求，路径设置父目录（凡是在父目录下的都可以发起请求，并给出响应）。</span></span><br><span class="line"><span class="comment">    next() 是回调函数的第三个参数，它是一个函数，调用函数后，可以触发后续的中间件</span></span><br><span class="line"><span class="comment">    next() 不能在响应处理完毕后调用</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;111&quot;</span>, <span class="title class_">Date</span>.<span class="title function_">now</span>())</span><br><span class="line">    <span class="comment">// res.send(&quot;&lt;h1&gt;111&lt;/h1&gt;&quot;)</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">next</span>() <span class="comment">// 放行，我不管了~~</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 可以在所有路由的后边配置错误路由（自定义404返回的数据，用户看到的内容）</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 只要这个中间件一执行，说明上边的地址都没有匹配</span></span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">404</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&quot;&lt;h1&gt;您访问的地址已被外星人劫持！&lt;/h1&gt;&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 启动服务器 listen表示监听</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">    app.listen(端口号) 用来启动服务器</span></span><br><span class="line"><span class="comment">    服务器启动后，我们便可以通过3000端口来访问了</span></span><br><span class="line"><span class="comment">    一个端口只能由一个服务器来监听</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;服务器已经启动~&quot;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<ul>
<li><p><strong>监视代码修改，自动重启服务器（本地）</strong></p>
<p>需要安装nodemon模块，当我们修改服务器代码后，会自动重启服务器.</p>
<p>使用方式:</p>
<ul>
<li><p>全局安装:npm i nodemon -g</p>
<p>启动:</p>
<ol>
<li>终端输入:nodemon</li>
<li>如果服务器入口文件不是index,那么就要使用:nodemon 全名xxx&#x2F;&#x2F; 运行指定的js</li>
</ol>
</li>
<li><p>在项目中安装:npm i nodemon -D(<strong>常用</strong>,使用-D表示当前安装模块只是在开发时使用(开发依赖,不是离开就不能用的),在打包时并不会给它整进去)</p>
<p>启动:npx nodemon</p>
</li>
</ul>
</li>
<li><p><strong>静态资源目录:</strong></p>
<p>有些时候我们希望用户访问服务器的某个页面时,可以给用户返回一些静态的资源,例如一些静态页面、图片、css、js文件等，服务器中的东西，对于外部来说都是不可见的,所以我们写的html页面，浏览器无法直接访问,如果希望浏览器可以访问，则需要将页面所在的目录设置静态资源目录.),那么这个时候就可以用到static中间件.</p>
<ul>
<li><p>设置static中间件后，浏览器访问时，会自动去public目录(有对应的public文件夹)寻找是否有匹配的静态资源</p>
</li>
<li><p>静态资源中间件跟路由是先匹配上边的,所以一定要把静态资源中间件放上面</p>
<p><strong>当前项目的inedx.js中：</strong></p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&quot;express&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"><span class="comment">//防止工作目录的原因导致路径问题所以用上path</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>)</span><br><span class="line"><span class="comment">// 配置请求体解析</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123; <span class="attr">extended</span>: <span class="literal">true</span> &#125;))</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个数组来存储用户信息（模拟的这是从数据库请求的来的数据）</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">USERS</span> = [</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="attr">username</span>: <span class="string">&quot;admin&quot;</span>,</span><br><span class="line">        <span class="attr">password</span>: <span class="string">&quot;123123&quot;</span>,</span><br><span class="line">        <span class="attr">nickname</span>: <span class="string">&quot;超级管理员&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="attr">username</span>: <span class="string">&quot;sunwukong&quot;</span>,</span><br><span class="line">        <span class="attr">password</span>: <span class="string">&quot;123456&quot;</span>,</span><br><span class="line">        <span class="attr">nickname</span>: <span class="string">&quot;齐天大圣&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 配置静态资源的路径</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// public &lt;==&gt; http://localhost:3000/</span></span><br><span class="line"><span class="comment">//第二个参数，虽然只是&quot;./public&quot;但它会默认去找public文件夹下的index文件，如果你不想找index文件那就写全路径</span></span><br><span class="line"><span class="comment">//此时public 就相当于 http://localhost:3000/ 所以访问根路径的时候就相当于访问public</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;./public&quot;</span>)))</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;public&quot;</span>)))</span><br><span class="line"><span class="comment">// 引入解析请求体的中间件，增加功能的中间件一般在上面写</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>())</span><br><span class="line"></span><br><span class="line"><span class="comment">//设置路由</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//这里虽然get的是根目录，但是前边使用了static中间件，然后在访问根目录时就会给用户返回他想要的静态资源（上面路径中设置好的）。或者可以理解为get的/会自动拼接到resolve里面第二个路径那里。</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">/* </span></span><br><span class="line"><span class="comment">        希望用户访问根目录时，可以给用户返回一个网页</span></span><br><span class="line"><span class="comment">        当然可以在这里用res.send()参数里面用拼接字符串的形式返回一个html页面，但是我直接写一个页面放在服务器里面不更好==&gt;public文件夹。</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&quot;怎么办呢？&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//做一个登录的功能</span></span><br><span class="line"><span class="comment">//前端以get方式请求</span></span><br><span class="line"><span class="comment">// /login --&gt;  http://localhost:3000/login</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/login&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 获取用户发送的数据</span></span><br><span class="line">    <span class="comment">// 通过req.query来获取查询字符串中的数据  req.query.username中username不是乱起的，是前端的name值叫这个后端才可以这么拿</span></span><br><span class="line">    <span class="keyword">if</span> (req.<span class="property">query</span>.<span class="property">username</span> === <span class="string">&quot;admin&quot;</span> &amp;&amp; req.<span class="property">query</span>.<span class="property">password</span> === <span class="string">&quot;123123&quot;</span>) &#123;</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">&quot;&lt;h1&gt;欢迎您回来！登录成功&lt;/h1&gt;&quot;</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">&quot;&lt;h1&gt;用户名或密码错误！&lt;/h1&gt;&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//前端以post方式请求</span></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&quot;/login&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 通过req.body来获取post请求的参数（请求体中的参数）</span></span><br><span class="line">    <span class="comment">// 默认情况下express不会自动解析请求体，需要通过中间件来为其增加功能</span></span><br><span class="line">    <span class="comment">// console.log(req.body)</span></span><br><span class="line">    <span class="keyword">const</span> username = req.<span class="property">body</span>.<span class="property">username</span></span><br><span class="line">    <span class="keyword">const</span> password = req.<span class="property">body</span>.<span class="property">password</span></span><br><span class="line">    <span class="comment">//方式1</span></span><br><span class="line">    <span class="comment">//获取到用户的用户名和密码后，需要根据用户名去用户的数组中查找用户</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> user <span class="keyword">of</span> <span class="variable constant_">USERS</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (user.<span class="property">username</span> === username) &#123;</span><br><span class="line">            <span class="comment">// 用户存在接着检查用户的密码</span></span><br><span class="line">            <span class="keyword">if</span> (user.<span class="property">password</span> === password) &#123;</span><br><span class="line">                <span class="comment">// 信息正确，登录成功</span></span><br><span class="line">                res.<span class="title function_">send</span>(<span class="string">`&lt;h1&gt;登录成功 <span class="subst">$&#123;user.nickname&#125;</span>&lt;/h1&gt;`</span>)</span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">`&lt;h1&gt;用户名或密码错误&lt;/h1&gt;`</span>)</span><br><span class="line">    <span class="comment">//方式二：数组find方法的使用</span></span><br><span class="line">    <span class="keyword">const</span> loginUser = <span class="variable constant_">USERS</span>.<span class="title function_">find</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> item.<span class="property">username</span> === username &amp;&amp; item.<span class="property">password</span> === password</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (loginUser) &#123;</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">`&lt;h1&gt;登录成功 <span class="subst">$&#123;loginUser.nickname&#125;</span>&lt;/h1&gt;`</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">`&lt;h1&gt;用户名或密码错误&lt;/h1&gt;`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​	 <strong>当前项目public文件夹下的index.html中：</strong></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;zh&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">h2</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/login&quot;</span> <span class="attr">method</span>=<span class="string">&quot;get/post&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span>&gt;</span>用户名 <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> /&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span>&gt;</span>密码 <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> /&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;登录&quot;</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">hr</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">h1</span>&gt;</span>我是一个网页，一个静态网页<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;./an.jpg&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>模板引擎：（李立超老师推荐的ejs，类似于Java中的jsp，运行于服务器，被服务器解析）</strong></p>
</li>
</ul>
<p>为啥要用模板引擎：比方说有一个需求，希望用户在访问students路由时，可以给用户返回一个显示有学生信息的页面，但是html页面属于静态页面，创建的时候什么样子，用户看到的就是什么样子，不会自动跟随服务器中数据的变化而变化，这时候我们就想要有这么一个东西，它呢长的像是个网页，但是他里边可以嵌入变量，这就引入了模板引擎。</p>
<blockquote>
<p>使用步骤：</p>
<p>注意，模板引擎需要被express渲染后才能使用（只是一个模板，无法被用户访问）</p>
</blockquote>
<p>首先需要安装ejs，然后配置express的模板引擎为ejs（模板引擎有很多，得给它通知一声），最后需要配置模板路径(一般开发的时候用不到，因为一个文件夹下是一个项目，不会出现不同启动方式，默认项目不同导致的路径问题)。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将ejs设置为默认的模板引擎</span></span><br><span class="line">app.<span class="title function_">set</span>(<span class="string">&quot;view engine&quot;</span>, <span class="string">&quot;ejs&quot;</span>)</span><br><span class="line"><span class="comment">// 配置模板的路径</span></span><br><span class="line">app.<span class="title function_">set</span>(<span class="string">&quot;views&quot;</span>, path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;views&quot;</span>))</span><br><span class="line"><span class="comment">//示例路由中的使用</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/hello&quot;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">// 第一个参数就是view文件夹内所用文件的路径（view不用写，它会默认去view内找模板），可以将一个对象作为render的第二个参数传递 ，这样在模板中可以访问到对象中的数据</span></span><br><span class="line">    res.<span class="title function_">render</span>(<span class="string">&quot;students&quot;</span>, &#123; <span class="attr">name</span>: <span class="string">&quot;孙悟空&quot;</span>, <span class="attr">age</span>: <span class="number">18</span>, <span class="attr">gender</span>: <span class="string">&quot;男&quot;</span> &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>view文件夹 内student模板的代码：</p>
<blockquote>
<p>语法：</p>
</blockquote>
<p> &lt;%&#x3D;变量名 %&gt;在ejs中输出内容时，它会自动对字符串中的特殊符号进行转义,这个设计主要是为了避免 xss 攻击</p>
<p> &lt;%- %&gt; 直接将内容输出(变量值为html代码时，也就是有标签存在时，不会将标签直接显示，而是作为HTML解析，显示出标签的作用) eg：{hello:”<h1>hhhh</h1>“}  模板中会显示一级标题的样式</p>
<p>  &lt;% %&gt;  可以在其中直接编写js代码，js代码会在服务器中执行</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html lang=&quot;zh&quot;&gt;</span><br><span class="line">    &lt;head&gt;</span><br><span class="line">        &lt;meta charset=&quot;UTF-8&quot; /&gt;</span><br><span class="line">        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;</span><br><span class="line">        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;</span><br><span class="line">        &lt;title&gt;这是ejs模板&lt;/title&gt;</span><br><span class="line">    &lt;/head&gt;</span><br><span class="line">    &lt;body&gt;</span><br><span class="line">        &lt;h1&gt;Hello EJS 哈哈&lt;/h1&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!-- </span><br><span class="line">            通过它可以将render传递进来的数据直接在网页中显示出来</span><br><span class="line">        --&gt;</span><br><span class="line">        &lt;%=name %&gt;</span><br><span class="line"></span><br><span class="line">        &lt;form action=&quot;/set_name&quot;&gt;</span><br><span class="line">            &lt;input type=&quot;text&quot; name=&quot;name&quot; placeholder=&quot;请输入你的名字&quot; /&gt;</span><br><span class="line">            &lt;button&gt;提交&lt;/button&gt;</span><br><span class="line">        &lt;/form&gt;</span><br><span class="line">		//这就是ejs的便利之处，它可以跟html代码交叉编写</span><br><span class="line">        &lt;% if(name === &quot;孙悟空&quot;) &#123;%&gt;</span><br><span class="line">        &lt;h2&gt;大师兄来了&lt;/h2&gt;</span><br><span class="line">        &lt;%&#125; else&#123;%&gt;</span><br><span class="line">        &lt;h2&gt;二师兄来了&lt;/h2&gt;</span><br><span class="line">        &lt;%&#125;%&gt;</span><br><span class="line">    &lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure>

<p><strong>有一个小练习，里面有一个数组的filter方法，以及重定向的操作。</strong></p>
<h2 id="6-路由Router（路由其实就是接口）"><a href="#6-路由Router（路由其实就是接口）" class="headerlink" title="6.路由Router（路由其实就是接口）"></a>6.路由Router（路由其实就是接口）</h2><p>一个项目有很多请求路由，这些路由都写在 app.js 文件里的话，就会让这个入口文件变得臃肿且难维护，加上 Node 是模块化编程，所以应该将这些 app.get() 和 app.post() 都抽取出来作为一个路由模块 <strong>router.js</strong>。</p>
<ul>
<li><p>使用步骤：</p>
<ol>
<li>首先在项目中建立一个routes文件夹，里面用来放置项目中各个部分的路由文件。</li>
<li>在入口文件中进行引入并use一下。</li>
<li>在每个路由文件中只需要将原本的app.get&#x2F;app.post换成router.xxx即可。</li>
</ol>
<blockquote>
<p>例如要展示student的信息，并且可以修改、删除、添加信息。</p>
</blockquote>
<p>student路由文件：student.js</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&quot;express&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> router = express.<span class="title class_">Router</span>()</span><br><span class="line"><span class="comment">//文件内存储学生信息数据，防止服务器重启后数据就没有了</span></span><br><span class="line"><span class="keyword">let</span> <span class="variable constant_">STUDENT_ARR</span> = <span class="built_in">require</span>(<span class="string">&quot;../data/students.json&quot;</span>)</span><br><span class="line"><span class="comment">//处理存储文件</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&quot;fs/promises&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 学生列表的路由</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&quot;/list&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>(req.<span class="property">cookies</span>.<span class="property">username</span>)&#123;</span><br><span class="line">        <span class="comment">//添加了一个students模板</span></span><br><span class="line">        res.<span class="title function_">render</span>(<span class="string">&quot;students&quot;</span>, &#123; <span class="attr">stus</span>: <span class="variable constant_">STUDENT_ARR</span> &#125;)</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        res.<span class="title function_">redirect</span>(<span class="string">&quot;/&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// res.render(&quot;students&quot;, &#123; stus: STUDENT_ARR &#125;)</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加学生的路由</span></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">&quot;/add&quot;</span>, <span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> id = <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">at</span>(-<span class="number">1</span>) ? <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">at</span>(-<span class="number">1</span>).<span class="property">id</span> + <span class="number">1</span> : <span class="number">1</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> newUser = &#123;</span><br><span class="line">        id,</span><br><span class="line">        <span class="attr">name</span>: req.<span class="property">body</span>.<span class="property">name</span>,</span><br><span class="line">        <span class="attr">age</span>: +req.<span class="property">body</span>.<span class="property">age</span>,</span><br><span class="line">        <span class="attr">gender</span>: req.<span class="property">body</span>.<span class="property">gender</span>,</span><br><span class="line">        <span class="attr">address</span>: req.<span class="property">body</span>.<span class="property">address</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">push</span>(newUser)</span><br><span class="line"></span><br><span class="line">    <span class="comment">//调用next交由后续路由继续处理</span></span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除学生的路由</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&quot;/delete&quot;</span>, <span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> id = +req.<span class="property">query</span>.<span class="property">id</span></span><br><span class="line"></span><br><span class="line">    <span class="variable constant_">STUDENT_ARR</span> = <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">filter</span>(<span class="function">(<span class="params">stu</span>) =&gt;</span> stu.<span class="property">id</span> !== id)</span><br><span class="line"></span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">&quot;/update-student&quot;</span>, <span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; id, name, age, gender, address &#125; = req.<span class="property">body</span></span><br><span class="line">    <span class="keyword">const</span> student = <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">find</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> item.<span class="property">id</span> == id)</span><br><span class="line"></span><br><span class="line">    student.<span class="property">name</span> = name</span><br><span class="line">    student.<span class="property">age</span> = +age</span><br><span class="line">    student.<span class="property">gender</span> = gender</span><br><span class="line">    student.<span class="property">address</span> = address</span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&quot;/to-update&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> id = +req.<span class="property">query</span>.<span class="property">id</span></span><br><span class="line">    <span class="keyword">const</span> student = <span class="variable constant_">STUDENT_ARR</span>.<span class="title function_">find</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> item.<span class="property">id</span> === id)</span><br><span class="line"></span><br><span class="line">    res.<span class="title function_">render</span>(<span class="string">&quot;update&quot;</span>, &#123; student &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理存储文件的中间件</span></span><br><span class="line">router.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    fs.<span class="title function_">writeFile</span>(</span><br><span class="line">        path.<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;../data/students.json&quot;</span>),</span><br><span class="line">        <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(<span class="variable constant_">STUDENT_ARR</span>)</span><br><span class="line">    )</span><br><span class="line">        .<span class="title function_">then</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            res.<span class="title function_">redirect</span>(<span class="string">&quot;/students/list&quot;</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">        .<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            res.<span class="title function_">send</span>(<span class="string">&quot;操作失败！&quot;</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = router</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>入口文件：index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//引入routes里面的路由</span></span><br><span class="line"><span class="keyword">const</span> studentRouter = <span class="built_in">require</span>(<span class="string">&quot;./routes/student&quot;</span>)</span><br><span class="line"><span class="comment">//use一下，使路由生效，使用第一个参数来解决不同路由文件内有相同路由名称的问题，有了第一个参数之后，前端再次进行访问路由时，就要在原本路由前加上 /students  即第一个参数名</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&quot;/students&quot;</span>, studentRouter)</span><br><span class="line"></span><br><span class="line"><span class="comment">//或者这样</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&quot;/students&quot;</span>, <span class="built_in">require</span>(<span class="string">&quot;./routes/student&quot;</span>))</span><br></pre></td></tr></table></figure>

<h2 id="7-cookie与session"><a href="#7-cookie与session" class="headerlink" title="7.cookie与session"></a>7.cookie与session</h2><p>​		</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="树洞">计算机学士&amp;化工硕士</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://baozi0625.gitee.io/tree-cave/2023/08/07/nodeJs/">https://baozi0625.gitee.io/tree-cave/2023/08/07/nodeJs/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://baozi0625.gitee.io/tree-cave" target="_blank">树洞</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tree-cave/tags/node-js/">node.js</a></div><div class="post_share"><div class="social-share" data-image="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/tree-cave/img/wechat.jpg" target="_blank"><img class="post-qr-code-img" src="/tree-cave/img/wechat.jpg" alt="wechat"/></a><div class="post-qr-code-desc">wechat</div></li><li class="reward-item"><a href="/tree-cave/img/alipay.jpg" target="_blank"><img class="post-qr-code-img" src="/tree-cave/img/alipay.jpg" alt="alipay"/></a><div class="post-qr-code-desc">alipay</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/tree-cave/2023/08/10/%E8%AE%BA%E6%96%87%E4%B8%AD%E7%9A%84%E5%90%8D%E8%AF%8D/" title="论文中一些词语的解释"><img class="cover" src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="onerror=null;src='/tree-cave/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">论文中一些词语的解释</div></div></a></div><div class="next-post pull-right"><a href="/tree-cave/2023/07/28/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%8A%A5%E9%94%99/" title="微信小程序导入别人的项目，打开之后出现Resource has expired. Please renewal fee, but if theproblem cannot be solved, contact us .的错误"><img class="cover" src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="onerror=null;src='/tree-cave/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">微信小程序导入别人的项目，打开之后出现Resource has expired. Please renewal fee, but if theproblem cannot be solved, contact us .的错误</div></div></a></div></nav><hr class="custom-hr"/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://s2.loli.net/2023/06/20/PkXRYIvxGBrtHZA.png" onerror="this.onerror=null;this.src='/tree-cave/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">计算机学士&amp;化工硕士</div><div class="author-info__description">一个对全栈开发感兴趣的化工硕士</div></div><div class="card-info-data site-data is-center"><a href="/tree-cave/archives/"><div class="headline">文章</div><div class="length-num">14</div></a><a href="/tree-cave/tags/"><div class="headline">标签</div><div class="length-num">11</div></a><a href="/tree-cave/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/baozi0625"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">保持热爱</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E8%AE%B0%E5%BD%95node-js%E7%9A%84%E5%AD%A6%E4%B9%A0%E8%BF%87%E7%A8%8B"><span class="toc-text">记录node.js的学习过程</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-%E5%BC%82%E6%AD%A5%E4%BB%A5%E5%8F%8Apromise"><span class="toc-text">1.异步以及promise</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-%E6%A8%A1%E5%9D%97%E5%8C%96"><span class="toc-text">2.模块化</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8NPM"><span class="toc-text">3.包管理器NPM</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1%E5%8F%8Ahttp%E5%8D%8F%E8%AE%AE%EF%BC%88%E8%B6%85%E5%93%A5%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0%EF%BC%89"><span class="toc-text">4.网络通信及http协议（超哥课堂笔记）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-express"><span class="toc-text">5.express</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-text">hhhh</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#6-%E8%B7%AF%E7%94%B1Router%EF%BC%88%E8%B7%AF%E7%94%B1%E5%85%B6%E5%AE%9E%E5%B0%B1%E6%98%AF%E6%8E%A5%E5%8F%A3%EF%BC%89"><span class="toc-text">6.路由Router（路由其实就是接口）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-cookie%E4%B8%8Esession"><span class="toc-text">7.cookie与session</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/tree-cave/2023/08/13/Vue%E8%B7%AF%E7%94%B1/" title="vue路由"><img src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="this.onerror=null;this.src='/tree-cave/img/404.jpg'" alt="vue路由"/></a><div class="content"><a class="title" href="/tree-cave/2023/08/13/Vue%E8%B7%AF%E7%94%B1/" title="vue路由">vue路由</a><time datetime="2023-08-12T16:00:00.000Z" title="发表于 2023-08-13 00:00:00">2023-08-13</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/tree-cave/2023/08/13/%E5%8C%96%E5%B7%A5%E5%8E%9F%E7%90%86/" title="化工原理中个人觉得需要记录的点"><img src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="this.onerror=null;this.src='/tree-cave/img/404.jpg'" alt="化工原理中个人觉得需要记录的点"/></a><div class="content"><a class="title" href="/tree-cave/2023/08/13/%E5%8C%96%E5%B7%A5%E5%8E%9F%E7%90%86/" title="化工原理中个人觉得需要记录的点">化工原理中个人觉得需要记录的点</a><time datetime="2023-08-12T16:00:00.000Z" title="发表于 2023-08-13 00:00:00">2023-08-13</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/tree-cave/2023/08/10/%E5%9B%9E%E9%A1%BE%E9%81%97%E5%BF%98%E7%9F%A5%E8%AF%86%E7%82%B9/" title="回顾遗忘的高中化学知识点"><img src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="this.onerror=null;this.src='/tree-cave/img/404.jpg'" alt="回顾遗忘的高中化学知识点"/></a><div class="content"><a class="title" href="/tree-cave/2023/08/10/%E5%9B%9E%E9%A1%BE%E9%81%97%E5%BF%98%E7%9F%A5%E8%AF%86%E7%82%B9/" title="回顾遗忘的高中化学知识点">回顾遗忘的高中化学知识点</a><time datetime="2023-08-09T16:00:00.000Z" title="发表于 2023-08-10 00:00:00">2023-08-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/tree-cave/2023/08/10/%E8%AE%BA%E6%96%87%E4%B8%AD%E7%9A%84%E5%90%8D%E8%AF%8D/" title="论文中一些词语的解释"><img src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="this.onerror=null;this.src='/tree-cave/img/404.jpg'" alt="论文中一些词语的解释"/></a><div class="content"><a class="title" href="/tree-cave/2023/08/10/%E8%AE%BA%E6%96%87%E4%B8%AD%E7%9A%84%E5%90%8D%E8%AF%8D/" title="论文中一些词语的解释">论文中一些词语的解释</a><time datetime="2023-08-09T16:00:00.000Z" title="发表于 2023-08-10 00:00:00">2023-08-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/tree-cave/2023/08/07/nodeJs/" title="node.js的学习"><img src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="this.onerror=null;this.src='/tree-cave/img/404.jpg'" alt="node.js的学习"/></a><div class="content"><a class="title" href="/tree-cave/2023/08/07/nodeJs/" title="node.js的学习">node.js的学习</a><time datetime="2023-08-06T16:00:00.000Z" title="发表于 2023-08-07 00:00:00">2023-08-07</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg')"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By 计算机学士&化工硕士</div><div class="footer_custom_text">Hi, welcome to my blog!</div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/tree-cave/js/utils.js"></script><script src="/tree-cave/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><div class="js-pjax"><script>function loadValine () {
  function initValine () {
    const valine = new Valine(Object.assign({
      el: '#vcomment',
      appId: 'l2iOGjxd8RLOsFZB2qG06CR1-gzGzoHsz',
      appKey: 'zl7gOCvEvrsrf3SNBcrJvDrj',
      avatar: 'monsterid',
      serverURLs: '',
      emojiMaps: "",
      path: window.location.pathname,
      visitor: false
    }, null))
  }

  if (typeof Valine === 'function') initValine() 
  else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
}

if ('Valine' === 'Valine' || !true) {
  if (true) btf.loadComment(document.getElementById('vcomment'),loadValine)
  else setTimeout(loadValine, 0)
} else {
  function loadOtherComment () {
    loadValine()
  }
}</script></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/tree-cave/js/search/local-search.js"></script></div></div></body></html>